package com.ray.business.api;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ray.base.service.BaseCustomerService;
import com.ray.base.service.compose.GoodsService;
import com.ray.base.table.entity.BaseCustomer;
import com.ray.base.table.vo.material.model.MaterialModelVO;
import com.ray.business.builder.BusinessBackBuilder;
import com.ray.business.builder.BusinessBackInBuilder;
import com.ray.business.builder.BusinessBackVOBuilder;
import com.ray.business.builder.BusinessGoodsVOBuilder;
import com.ray.business.check.BusinessBackCheck;
import com.ray.business.check.BusinessCheck;
import com.ray.business.check.BusinessOutCheck;
import com.ray.business.enums.BusinessBackStatusEnum;
import com.ray.business.enums.BusinessTypeEnum;
import com.ray.business.service.*;
import com.ray.business.table.dto.BusinessBackQueryDTO;
import com.ray.business.table.entity.*;
import com.ray.business.table.params.business.back.BusinessBackCreateParams;
import com.ray.business.table.params.business.back.BusinessBackQueryParams;
import com.ray.business.table.vo.BusinessBackVO;
import com.ray.business.table.vo.BusinessGoodsVO;
import com.ray.system.builder.CommonPageBuilder;
import com.ray.validate.support.utils.ValidateUtil;
import com.ray.wms.builder.GoodsBuilder;
import com.ray.wms.service.WmsWarehouseService;
import com.ray.wms.service.compose.InService;
import com.ray.wms.table.dto.GoodsDTO;
import com.ray.wms.table.dto.OrderCreateDTO;
import com.ray.wms.table.entity.WmsWarehouse;
import com.ray.woodencreate.beans.LoginUser;
import com.ray.woodencreate.exception.BusinessExceptionFactory;
import com.ray.woodencreate.page.CommonPage;
import com.ray.woodencreate.result.MsgCodeConstant;
import com.ray.woodencreate.result.Result;
import com.ray.woodencreate.result.ResultFactory;
import com.ray.woodencreate.util.Assert;
import com.ray.woodencreate.util.LogInUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bo shen
 * @Description: 订单相关服务
 * @Class: BusinessBackApi
 * @Package com.ray.base.api
 * @date 2020/5/27 11:15
 * @company <p>Ray快速开发平台</p>
 * @updateRecord time(修改时间)  author(修改人)   desc(修改内容)
 */
@Service
@Slf4j
public class BusinessBackApi {

    @Autowired
    private ProdStepService prodStepService;
    @Autowired
    private BaseCustomerService baseCustomerService;
    @Autowired
    private ProdBusinessBackService prodBusinessBackService;
    @Autowired
    private WmsWarehouseService wmsWarehouseService;
    @Autowired
    private ProdBusinessService prodBusinessService;
    @Autowired
    private ProdBusinessBackInService prodBusinessBackInService;
    @Autowired
    private ProdBusinessOutService prodBusinessOutService;
    @Autowired
    private ProdBusinessInService prodBusinessInService;
    @Autowired
    private InService inService;
    @Autowired
    private GoodsService goodsService;

    /**
     * 查询订单列表信息 分页  非删除的
     *
     * @param queryParams
     * @return
     */
    public Result<IPage<BusinessBackVO>> pageBusinessBacks(CommonPage<BusinessBackQueryParams, Page<BusinessBackVO>> queryParams) {
        Assert.notNull(queryParams, "参数[queryParams]不能为空");
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        Map<String, BaseCustomer> baseCustomerMap = new HashMap<>();
        Map<String, WmsWarehouse> wmsWarehouseMap = new HashMap<>();
        Map<String, ProdStep> stepMap = new HashMap<>();
        CommonPageBuilder<BusinessBackQueryDTO, ProdBusinessBack> commonPageBuilder = new CommonPageBuilder<>(BusinessBackQueryDTO.class);
        commonPageBuilder.appendEntity(queryParams.getEntity()).appendQuery(queryParams.getQuery()).appendPage(queryParams.getPage());
        IPage<ProdBusinessBack> page = prodBusinessBackService.page(commonPageBuilder.bulid(), loginUser);
        List<ProdBusinessBack> orders = page.getRecords();
        //结果对象
        IPage<BusinessBackVO> pageList = new Page<>();
        pageList.setTotal(page.getTotal());
        pageList.setCurrent(page.getCurrent());
        pageList.setSize(page.getSize());
        //查询到结果 数据转换
        if (ObjectUtil.isNotNull(orders)) {
            pageList.setRecords(orders.stream().map(sysBusinessBack -> {
                //查询客信息
                BaseCustomer baseCustomer = baseCustomerMap.get(sysBusinessBack.getCustomerCode());
                if (ObjectUtil.isEmpty(baseCustomer)) {
                    baseCustomer = baseCustomerService.queryCustomerByCustomerCode(sysBusinessBack.getCustomerCode(), loginUser);
                    baseCustomerMap.put(sysBusinessBack.getCustomerCode(), baseCustomer);
                }
                //查询仓库信息
                WmsWarehouse wmsWarehouse = wmsWarehouseMap.get(sysBusinessBack.getWarehouseCode());
                if (ObjectUtil.isEmpty(wmsWarehouse)) {
                    wmsWarehouse = wmsWarehouseService.queryWarehouseByWarehouseCode(sysBusinessBack.getWarehouseCode(), loginUser);
                    wmsWarehouseMap.put(wmsWarehouse.getWarehouseCode(), wmsWarehouse);
                }
                //工序信息
                ProdStep prodStep = stepMap.get(sysBusinessBack.getStepCode());
                if (ObjectUtil.isEmpty(prodStep)) {
                    prodStep = prodStepService.queryStepByStepCode(sysBusinessBack.getStepCode(), loginUser);
                    stepMap.put(sysBusinessBack.getStepCode(), prodStep);
                }
                return new BusinessBackVOBuilder().append(sysBusinessBack).append(baseCustomer).append(wmsWarehouse).append(prodStep).bulid();
            }).collect(Collectors.toList()));
        } else {
            pageList.setRecords(new ArrayList<>());
        }
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, pageList);
    }


    /**
     * 创建加工业务出库单
     *
     * @return
     */
    @Transactional
    public Result<String> createBusinessBack(BusinessBackCreateParams createParams) {
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        ProdBusiness business = prodBusinessService.queryBusinessByBusinessCode(createParams.getBusinessCode(), loginUser);
        new BusinessCheck(business).checkNull("业务加工单不存在").checkCanBack("订单不能退料");

        BusinessBackBuilder businessBackBuilder = new BusinessBackBuilder();
        businessBackBuilder.append(business).appendCreate(loginUser).appendStatus(BusinessBackStatusEnum.UN_CHECK.getValue());
        //总数统计
        List<BigDecimal> quantitys = new ArrayList<>();
        //卷数
        List<Integer> juanTotal = new ArrayList<>();
        List<String> keys = new ArrayList<>();
        List<ProdBusinessBackIn> prodBusinessBackIns = createParams.getGoods().stream().map(goodsParams -> {
            if (keys.contains(goodsParams.getKey())) {
                log.info("物料重复:{}", JSON.toJSONString(goodsParams));
                throw BusinessExceptionFactory.newException("物料重复");
            }
            keys.add(goodsParams.getKey());
            BusinessBackInBuilder businessBackInBuilder = new BusinessBackInBuilder();
            Assert.hasLength(goodsParams.getCode(), "出库数据code不能为空");
            ProdBusinessOut prodBusinessOut = prodBusinessOutService.getGoodsByCode(goodsParams.getCode(), loginUser);
            new BusinessOutCheck(prodBusinessOut).checkNull("出库单记录不存在")
                    .checkBusinessCode(createParams.getBusinessCode(), "加工单出库数据不一致").checkBackQuantity(goodsParams.getQuantity(), "退料不够");
            quantitys.add(goodsParams.getQuantity());
            //添加卷数
            juanTotal.add(goodsParams.getTotal());
            if (!prodBusinessOutService.updateQuantity(goodsParams.getCode(), prodBusinessOut.getQuantity().subtract(goodsParams.getQuantity())
                    , prodBusinessOut.getUpdateVersion(), loginUser)) {
                log.info("退料更新数量异常");
                throw BusinessExceptionFactory.newException("退料更新数量异常");
            }
            businessBackInBuilder.append(goodsParams).appendOutCode(goodsParams.getCode()).appendBusinessCode(business.getBusinessCode())
                    .appendBackCode(businessBackBuilder.getCode()).appendCreate(loginUser);
            return businessBackInBuilder.bulid();
        }).collect(Collectors.toList());

        BigDecimal total = quantitys.stream().reduce(BigDecimal::add).get();
        //统计卷数
        Integer juans = juanTotal.stream().mapToInt(Integer::intValue).sum();
        businessBackBuilder.append(total);
        businessBackBuilder.appendJuan(juans);
        //更新订单数据
        if (!prodBusinessService.updateQuantity(business.getBusinessCode(), business.getQuantity().subtract(total)
                , business.getTotal() - juans, business.getUpdateVersion(), loginUser)) {
            log.info("退料更新数量异常");
            throw BusinessExceptionFactory.newException("退料更新数量异常");
        }
        //保存数据
        prodBusinessBackService.save(businessBackBuilder.bulid());
        //保存明细数据
        prodBusinessBackInService.saveBatch(prodBusinessBackIns);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, businessBackBuilder.getCode());
    }


    /**
     * 审核
     *
     * @return
     */
    @Transactional
    public Result<String> passBusinessBack(String backCode) {
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        ProdBusinessBack businessBack = prodBusinessBackService.queryBusinessBackByBackCode(backCode, loginUser);
        new BusinessBackCheck(businessBack).checkNull("业务加工退料单不存在").checkCanCheck("订单已审核");

        BusinessBackBuilder businessBuilder = new BusinessBackBuilder();
        businessBuilder.appendCode(backCode).appendEdit(loginUser).appendStatus(BusinessBackStatusEnum.UN_IN.getValue());
        //更新
        prodBusinessBackService.edit(businessBuilder.bulid(), loginUser);
        //查询
        OrderCreateDTO orderCreateDTO = new OrderCreateDTO();
        orderCreateDTO.setBusinessOrderNo(businessBack.getOrderNo());
        orderCreateDTO.setBusinessCode(businessBack.getBackCode());
        orderCreateDTO.setWarehouseCode(businessBack.getWarehouseCode());
        //查询订单商品
        List<ProdBusinessBackIn> records = prodBusinessBackInService.listAll(businessBack.getBackCode(), loginUser);
        List<GoodsDTO> goodsDTOS = records.stream().map(prodBusinessBackIn -> {
            return new GoodsBuilder().append(prodBusinessBackIn).appendOrderNo(businessBack.getOrderNo()).bulid();
        }).collect(Collectors.toList());
        orderCreateDTO.setGoodsDTOS(goodsDTOS);
        //创建订单
        inService.createOrderIn(orderCreateDTO, loginUser);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, backCode);
    }


    /**
     * 删除
     *
     * @return
     */
    @Transactional
    public Result<String> deleteBusinessBack(String backCode) {
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        ProdBusinessBack businessBack = prodBusinessBackService.queryBusinessBackByBackCode(backCode, loginUser);
        new BusinessBackCheck(businessBack).checkNull("业务加工退料单不存在").checkCanDelete("订单不能删除");

        ProdBusiness business = prodBusinessService.queryBusinessByBusinessCode(businessBack.getBusinessCode(), loginUser);
        new BusinessCheck(business).checkNull("业务加工单不存在");
        BusinessBackBuilder businessBuilder = new BusinessBackBuilder();
        businessBuilder.appendCode(backCode).appendEdit(loginUser).delete();
        //更新
        prodBusinessBackService.edit(businessBuilder.bulid(), loginUser);
        //还原数据
        backRecord(backCode, business, loginUser);
        //删除原有的记录
        prodBusinessBackInService.deleteByBackCode(backCode, loginUser);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, backCode);
    }


    /**
     * 删除
     *
     * @return
     */
    @Transactional
    public Result<String> cancelBusinessBack(String backCode) {
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        ProdBusinessBack businessBack = prodBusinessBackService.queryBusinessBackByBackCode(backCode, loginUser);
        new BusinessBackCheck(businessBack).checkNull("业务加工退料单不存在").checkCanCancel("订单不能取消");
        ProdBusiness business = prodBusinessService.queryBusinessByBusinessCode(businessBack.getBusinessCode(), loginUser);
        new BusinessCheck(business).checkNull("业务加工单不存在");
        BusinessBackBuilder businessBuilder = new BusinessBackBuilder();
        businessBuilder.appendCode(backCode).appendEdit(loginUser).appendStatus(BusinessBackStatusEnum.CANCEL.getValue());
        //更新
        prodBusinessBackService.edit(businessBuilder.bulid(), loginUser);
        //还原数据
        backRecord(backCode, business, loginUser);
        //取消出入库单
        inService.invalidOrderBusinessCode(backCode, loginUser);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, backCode);
    }


    /**
     * 详情
     *
     * @return
     */
    @Transactional
    public Result<BusinessBackVO> viewBusinessBack(String backCode) {
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        ProdBusinessBack businessBack = prodBusinessBackService.queryBusinessBackByBackCode(backCode, loginUser);
        new BusinessBackCheck(businessBack).checkNull("业务加工退料单不存在");
        BusinessBackVOBuilder businessVOBuilder = new BusinessBackVOBuilder();
        businessVOBuilder.append(businessBack);
        //查询客户信息
        BaseCustomer baseCustomer = baseCustomerService.queryCustomerByCustomerCode(businessBack.getCustomerCode(), loginUser);
        businessVOBuilder.append(baseCustomer);
        WmsWarehouse wmsWarehouse = wmsWarehouseService.queryWarehouseByWarehouseCode(businessBack.getWarehouseCode(), loginUser);
        businessVOBuilder.append(wmsWarehouse);
        Map<String, MaterialModelVO> modelMap = new HashMap<>();
        List<BusinessGoodsVO> goodsVOS = prodBusinessBackInService.listAll(businessBack.getBackCode(), loginUser)
                .stream().map(prodBusinessBackIn -> {
                    BusinessGoodsVOBuilder businessGoodsVOBuilder = new BusinessGoodsVOBuilder();
                    MaterialModelVO materialModelVO = modelMap.get(prodBusinessBackIn.getGoodsCode());
                    if (ObjectUtil.isNull(materialModelVO)) {
                        materialModelVO = goodsService.queryGoodsByCode(prodBusinessBackIn.getGoodsCode(), loginUser);
                        modelMap.put(prodBusinessBackIn.getGoodsCode(), materialModelVO);
                    }
                    businessGoodsVOBuilder.append(materialModelVO).append(prodBusinessBackIn);
                    return businessGoodsVOBuilder.bulid();
                }).collect(Collectors.toList());
        businessVOBuilder.append(goodsVOS);
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, businessVOBuilder.bulid());
    }

    /**
     * 查询加工单
     *
     * @param queryParams
     * @return
     */
    public Result<List<BusinessGoodsVO>> listBackOutGoods(BusinessBackQueryParams queryParams) {
        ValidateUtil.validate(queryParams);
        //当前登录对象
        LoginUser loginUser = LogInUserUtil.get();
        Map<String, MaterialModelVO> modelMap = new HashMap<>();
        List<BusinessGoodsVO> goodsVOS = prodBusinessOutService.list(Arrays.asList(queryParams.getBusinessCode()), loginUser)
                .stream().map(prodBusinessOut -> {
                    //加工入库数量
                    BusinessGoodsVOBuilder businessGoodsVOBuilder = new BusinessGoodsVOBuilder();
                    MaterialModelVO materialModelVO = modelMap.get(prodBusinessOut.getGoodsCode());
                    if (ObjectUtil.isNull(materialModelVO)) {
                        materialModelVO = goodsService.queryGoodsByCode(prodBusinessOut.getGoodsCode(), loginUser);
                        modelMap.put(prodBusinessOut.getGoodsCode(), materialModelVO);
                    }
                    businessGoodsVOBuilder.append(materialModelVO).append(prodBusinessOut);
                    return businessGoodsVOBuilder.bulid();
                }).collect(Collectors.toList());
        return ResultFactory.createSuccessResult(MsgCodeConstant.Success.SUC00000002, goodsVOS);
    }

    /**
     * 还原数据
     *
     * @param backCode
     */
    private void backRecord(String backCode, ProdBusiness business, LoginUser loginUser) {
        //查询订单商品
        List<ProdBusinessBackIn> records = prodBusinessBackInService.listAll(backCode, loginUser);
        //总数统计
        List<BigDecimal> quantitys = new ArrayList<>();
        //卷数
        List<Integer> juanTotal = new ArrayList<>();
        List<String> keys = new ArrayList<>();
        records.forEach(goodsParams -> {
            ProdBusinessOut prodBusinessOut = prodBusinessOutService.getUsableGoodsByCode(goodsParams.getOutCode(), loginUser);
            quantitys.add(goodsParams.getQuantity());
            //卷数
            juanTotal.add(goodsParams.getTotal());
            if (!prodBusinessOutService.updateQuantity(goodsParams.getOutCode(), prodBusinessOut.getQuantity().add(goodsParams.getQuantity())
                    , prodBusinessOut.getUpdateVersion(), loginUser)) {
                log.info("退料更新数量异常");
                throw BusinessExceptionFactory.newException("退料更新数量异常");
            }
        });

        BigDecimal total = quantitys.stream().reduce(BigDecimal::add).get();
        //统计卷数
        Integer juans = juanTotal.stream().mapToInt(Integer::intValue).sum();
        //更新订单数据
        if (!prodBusinessService.updateQuantity(business.getBusinessCode(), business.getQuantity().add(total)
                , business.getTotal() + juans, business.getUpdateVersion(), loginUser)) {
            log.info("退料更新数量异常");
            throw BusinessExceptionFactory.newException("退料更新数量异常");
        }
    }


}
